package com.qinglei.recoup.system.task;

import com.qinglei.recoup.common.domain.ActiveUser;
import com.qinglei.recoup.common.domain.CommonConstant;
import com.qinglei.recoup.common.service.CacheService;
import com.qinglei.recoup.common.service.RedisService;
import com.qinglei.recoup.common.utils.JsonUtils;
import com.qinglei.recoup.system.domain.EventBedBO;
import com.qinglei.recoup.system.enums.EventEnum;
import com.qinglei.recoup.system.service.EventLogService;
import com.qinglei.recoup.system.service.NurseBedService;
import com.qinglei.recoup.system.service.NurseOnlineService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 主要用于定时删除 Redis中 key为 recoup.user.active 中
 * 已经过期的 score
 */
@Slf4j
@Component
public class UserTask {

    @Autowired
    private RedisService redisService;
    @Resource
    private CacheService cacheService;
    @Resource
    private NurseBedService nurseBedService;
    @Resource
    private EventLogService eventLogService;
    @Autowired
    private NurseOnlineService nurseOnlineService;

    @Value("${recoup.online-check-timeout}")
    private Long onlineCheckTimeout;

    //    @Scheduled(fixedRate = 60000)
    public void checkOnlineStatus() {
        log.debug("check user online start");
        try {
            Long expireTime = System.currentTimeMillis() - this.onlineCheckTimeout * 1000;
            Set<String> expireUserIds = redisService.zrangeByScore(CommonConstant.ACTIVE_USERS_ZSET_PREFIX,
                    "-inf", String.valueOf(expireTime));
            if (CollectionUtils.isNotEmpty(expireUserIds)) {
                log.info("expired users: {}", expireUserIds);
                expireUserIds.forEach(userId -> {
                    log.info("save user offline time userId:{}", userId);
                    try {
                        nurseOnlineService.saveLogout(Long.valueOf(userId));
                    } catch (Exception e) {
                        log.error("save user offline time error userId:{}", userId, e);
                    }
                });
                redisService.zrem(CommonConstant.ACTIVE_USERS_ZSET_PREFIX, expireUserIds.toArray(new String[expireUserIds.size()]));
            }
        } catch (Exception e) {
            log.error("check user online error", e);
        }
    }

    public void checkTakeEventTimeOut() {
        log.debug("checkTakeEventTimeOut run");
        try {
            long expire = System.currentTimeMillis() / 1000;
            Set<String> eventBedBOs = redisService.zrangeByScore(CommonConstant.WAIT_TAKE_EVENT_ZSET_PREFIX,
                    "-inf", String.valueOf(expire));
            if (CollectionUtils.isNotEmpty(eventBedBOs)) {
                redisService.zrem(CommonConstant.WAIT_TAKE_EVENT_ZSET_PREFIX, eventBedBOs.toArray(new String[eventBedBOs.size()]));
                log.info("TakeEventTimeOut eventBedBOs:{}", eventBedBOs);
                List<ActiveUser> onlineNurse = cacheService.getOnlineNurse();
                final Set<Long> onlineNurseIds = onlineNurse.stream().map(ActiveUser::getUserId).collect(Collectors.toSet());
                eventBedBOs.forEach(val -> {
                    try {
                        EventBedBO eventBedBO = JsonUtils.jsonToBean(val, EventBedBO.class);
                        Set<Long> nurseIds = nurseBedService.getNurseIdsByBed(eventBedBO.getBedId());
                        Collection<Long> intersection = CollectionUtils.intersection(onlineNurseIds, nurseIds);
                        log.info("TakeEventTimeOut send eventBedBO:{}, intersection:{}", eventBedBO, intersection);
                        for (Long userId : intersection) {
                            eventLogService.procEventLog(eventBedBO.getBedId(), userId, eventBedBO.getEventId(),
                                    EventEnum.EVENT_PROC_UNFINISHED.getCode(), null, eventBedBO.getTenantId());
                        }
                    } catch (Exception e) {
                        log.error("checkTakeEventTimeOut error eventBedBO:{}", val, e);
                    }
                });

            }

        } catch (Exception e) {
            log.error("checkTakeEventTimeOut error", e);
        }
    }

}
